﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace SpaceGame
{
    public abstract class Entity
    {
        protected SpriteTable sprites;
        private float rotation;
        private float rotationSpeed;
        private float scale;
        private Rectangle hitbox;
        private Vector2 velocity;
        private Vector2 origin;
        private Matrix transform;   //change in rotation
        private Entity parent;
        private readonly Vector2 initOrigOffset;   //initial origin offset from parent
        private float rotOffset;    //difference in radians from parent

        //Update rotation with parent's rotation if necessary
        public float Rotation
        {
            get { return rotation; }
            set
            {
                if (parent == null)
                {
                    rotation = value;
                }
                else
                {
                    rotation = parent.Rotation + rotOffset + value - rotation;
                    rotOffset = rotation - parent.Rotation;
                }
                rotation %= (2 * MathHelper.Pi);
                transform = Matrix.CreateRotationZ(rotation);
                if (parent != null)
                {
                    transform *= parent.transform;
                }
            }
        }

        //For cursor
        public float AbsoluteRotation
        {
            set
            {
                rotation = value % (2 * MathHelper.Pi);
                rotOffset = rotation - parent.Rotation;
            }
        }

        public float Scale
        {
            get { return scale; }
            set { scale = value; }
        }
        
        //Vector from parent origin to this origin
        private Vector2 getParentVector(){
            if (parent == null)
            {
                return Vector2.Zero;
            }
            return origin - parent.origin;
        }

        public Sprite Sprite
        {
            get { return sprites.CurrentSprite; }
        }

        //Sprite position: where the sprite origin should be drawn
        public virtual Vector2 Position
        {
            get { return Origin; }
        }

        public Vector2 Velocity
        {
            get { return velocity; }
            set { velocity = value; }
        }

        public float RotationSpeed
        {
            get { return rotationSpeed; }
            set { rotationSpeed = value; }
        }

        public Vector2 Origin
        {
            get { return origin; }
            set 
            {
                //Calculate immediate positional change
                if (parent == null)
                {
                    origin = value;
                }
                else
                {
                    origin = parent.Origin + Vector2.Transform(initOrigOffset, parent.transform) + value - origin;
                }
            }
        }

        protected abstract float Z
        {
            get;
        }

        public Entity(ContentManager content, float rotation, float scale, Vector2 origin, Entity parent = null)
        {
            Rotation = rotation;
            Scale = scale;
            Origin = origin;
            this.parent = parent;
            initOrigOffset = getParentVector();
            LoadContent(content);
        }

        public virtual void Draw(SpriteBatch spriteBatch)
        {
            sprites.CurrentSprite.Draw(Position, rotation, Z, spriteBatch);
        }
        
        public virtual void Update(GameTime gameTime)
        {
            Rotation += RotationSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            Origin += Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
        }

        protected virtual void LoadContent(ContentManager content)
        {
            sprites = new SpriteTable();
        }

        protected void addSprite(ContentManager content, String path, String key, Point[] frames = null)
        {
            Sprite sprite = new Sprite(content.Load<Texture2D>(path));
            sprites.addSprite(key, sprite);
            if (frames != null)
            {
                foreach (Point frame in frames)
                {
                    sprite.addFrame(frame);
                }
            }
        }
    }
}
